Documentation Index Fetch the complete documentation index at: https://docs.ctrlplane.dev/llms.txt
Use this file to discover all available pages before exploring further.
Ctrlplane uses CEL (Common Expression Language)
for writing powerful selectors and matching expressions. CEL is a simple, fast,
and safe expression language developed by Google.
Overview
CEL expressions are used in:
Resource selectors — Match resources to environments
Policy selectors — Target policies to specific releases
Relationship rules — Define how entities connect
# Example: Environment resource selector
resourceSelector : resource.metadata["environment"] == "production"
# Example: Policy selector
selector : environment.name == "Production" && deployment.metadata["critical"] == "true"
Basic Syntax
Accessing Fields
# Direct field access
resource.name
resource.kind
resource.identifier
# Metadata access (map)
resource.metadata["environment"]
resource.metadata["region"]
# Config access
resource.config["namespace"]
Comparison Operators
Operator Description Example ==Equal resource.kind == "KubernetesCluster"!=Not equal resource.metadata["env"] != "dev"<Less than resource.metadata["priority"] < "5">Greater than resource.metadata["replicas"] > "1"<=Less or equal version.metadata["build"] <= "100">=Greater or equal resource.metadata["tier"] >= "2"
Logical Operators
Operator Description Example &&Logical AND a == "x" && b == "y"||Logical OR a == "x" || a == "y"!Logical NOT !resource.metadata["deprecated"]
Arithmetic Operators
Operator Description Example +Addition / Concatenation "prefix-" + resource.name-Subtraction int(a) - int(b)*Multiplication int(a) * 2/Division int(a) / 2%Modulo int(a) % 2 == 0
Available Variables
Resource Context
When writing resource selectors:
Variable Type Description resource.idstring Unique resource ID resource.namestring Resource display name resource.kindstring Resource type (e.g., KubernetesCluster) resource.identifierstring External identifier resource.versionstring Resource version resource.metadatamap Key-value metadata resource.configmap Resource configuration
Environment Context
When writing environment selectors:
Variable Type Description environment.idstring Environment ID environment.namestring Environment name environment.metadatamap Environment metadata
Deployment Context
When writing deployment selectors:
Variable Type Description deployment.idstring Deployment ID deployment.namestring Deployment name deployment.metadatamap Deployment metadata
Version Context
When writing version selectors:
Variable Type Description version.idstring Version ID version.tagstring Version tag version.namestring Version name version.metadatamap Version metadata
String Functions
contains
Check if a string contains a substring:
resource.name.contains("prod")
resource.metadata["tags"].contains("critical")
startsWith
Check if a string starts with a prefix:
resource.identifier.startsWith("k8s-")
resource.metadata["region"].startsWith("us-")
endsWith
Check if a string ends with a suffix:
resource.name.endsWith("-cluster")
resource.metadata["zone"].endsWith("a")
matches
Regular expression matching:
# Match identifiers like prod-cluster-1, prod-cluster-2
resource.identifier.matches("^prod-cluster-[0-9]+$")
# Match any US region
resource.metadata["region"].matches("^us-(east|west)-[0-9]$")
size
Get string length:
resource.name.size() > 0
resource.metadata["description"].size() < 100
toLowerCase / toUpperCase
Case conversion:
resource.metadata["env"].toLowerCase() == "production"
List Operations
Check if a value is in a list:
resource.metadata["region"] in ["us-east-1", "us-west-2", "eu-west-1"]
resource.kind in ["KubernetesCluster", "KubernetesNamespace"]
size
Get list length:
resource.metadata["tags"].size() > 0
exists
Check if any element matches:
# Check if any tag starts with "team-"
resource.metadata["tags"].exists(t, t.startsWith("team-"))
all
Check if all elements match:
# Check if all regions are in US
resource.metadata["regions"].all(r, r.startsWith("us-"))
Map Operations
has
Check if a key exists in a map:
has(resource.metadata["team"])
has(resource.config["namespace"])
This is safer than direct access when the key might not exist.
Key Access
Access map values:
resource.metadata["environment"]
resource.config["server"]
Conditional Expressions
Ternary Operator
resource.metadata["tier"] == "critical" ? "high-priority" : "normal"
Null-Safe Access
Use has() for optional fields:
has(resource.metadata["deprecated"]) && resource.metadata["deprecated"] == "true"
Or use the default pattern:
# Default to empty string if not present
(has(resource.metadata["team"]) ? resource.metadata["team"] : "") == "platform"
Common Patterns
Production Resources
resource.metadata["environment"] == "production"
Multi-Region Targeting
resource.metadata["region"] in ["us-east-1", "us-west-2"]
Kind Filtering
resource.kind == "KubernetesCluster" &&
resource.metadata["environment"] == "production"
Team-Based Selection
resource.metadata["team"] == "platform" ||
resource.metadata["team"] == "infrastructure"
Exclude Deprecated
!has(resource.metadata["deprecated"]) ||
resource.metadata["deprecated"] != "true"
Critical Tier in Production
resource.metadata["environment"] == "production" &&
resource.metadata["tier"] == "critical"
US Regions Only
resource.metadata["region"].startsWith("us-")
Canary Resources
resource.metadata["environment"] == "production" &&
has(resource.metadata["canary"]) &&
resource.metadata["canary"] == "true"
Complex Multi-Condition
(resource.metadata["environment"] == "production" &&
resource.metadata["region"] in ["us-east-1", "us-west-2"]) ||
(resource.metadata["environment"] == "staging" &&
resource.metadata["region"] == "us-east-1")
Policy Selector Examples
Target Production Environment
environment.name == "Production"
Target Critical Deployments
deployment.metadata["tier"] == "critical"
Target Specific Environment + Deployment
environment.name == "Production" &&
deployment.metadata["requires-approval"] == "true"
Version Filtering
version.tag.startsWith("v2.") &&
!version.tag.contains("beta")
Relationship Rule Examples
Match by Region
# fromSelector for VPCs
resource.kind == "vpc"
# toSelector for clusters
resource.kind == "KubernetesCluster"
# Property matcher expression
from.metadata["region"] == to.metadata["region"]
Match by Account
from.metadata["account"] == to.metadata["account"] &&
from.metadata["region"] == to.metadata["region"]
Type Coercion
CEL is strongly typed. Use these functions to convert types:
String to Integer
int(resource.metadata["replicas"]) > 3
Integer to String
string(42) == resource.metadata["count"]
Type Checking
type(resource.metadata["count"]) == string
Error Handling
Safe Field Access
Always use has() for optional fields to avoid runtime errors:
# Bad: may error if "team" doesn't exist
resource.metadata["team"] == "platform"
# Good: safe access
has(resource.metadata["team"]) && resource.metadata["team"] == "platform"
Default Values
Provide defaults for optional fields:
# Use empty string as default
(has(resource.metadata["tier"]) ? resource.metadata["tier"] : "standard") == "critical"
Prefer Simple Expressions
# Fast: simple equality
resource.metadata["env"] == "production"
# Slower: regex matching
resource.identifier.matches("^prod-.*")
Short-Circuit Evaluation
CEL uses short-circuit evaluation. Put cheap checks first:
# Good: check env first (fast), then regex (slow)
resource.metadata["env"] == "production" &&
resource.identifier.matches("^prod-cluster-[0-9]+$")
Avoid Redundant Checks
# Bad: redundant
resource.kind == "KubernetesCluster" &&
resource.kind != "VM"
# Good: single check
resource.kind == "KubernetesCluster"
Debugging
Test Expressions
Use the API to test your CEL expressions:
curl -X POST "https://your-ctrlplane-instance.com/api/v1/workspaces/{workspaceId}/resources/query" \
-H "Authorization: Bearer $CTRLPLANE_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"filter": "resource.metadata[\"environment\"] == \"production\""
}'
Common Errors
Error Cause Fix no such keyAccessing missing map key Use has() check type mismatchComparing different types Use type coercion syntax errorInvalid CEL syntax Check quotes, brackets undeclared referenceUnknown variable Check variable names
Escaping Quotes
In YAML, escape quotes properly:
# Single quotes around expression, double quotes inside
resourceSelector : 'resource.metadata["environment"] == "production"'
# Or use YAML literal block
resourceSelector : |
resource.metadata["environment"] == "production"
In JSON:
{
"filter" : "resource.metadata[ \" environment \" ] == \" production \" "
}
Reference
Reserved Keywords
These words are reserved in CEL:
true, false, null
in
as
break, const, continue, else, for, function, if, import, let, loop, package, namespace, return, var, void, while
Operator Precedence
From highest to lowest:
() - Grouping
. [] - Member access
- ! - Unary
* / % - Multiplicative
+ - - Additive
< <= > >= in - Relational
== != - Equality
&& - Logical AND
|| - Logical OR
?: - Conditional
Next Steps
Selectors Use CEL in selectors
Relationships CEL in relationship rules
Policies Target policies with CEL
Environments Dynamic environment membership