GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • docs home page
  • Deployment
  • Inventory
  • Reference
  • Architecture
  • GitHub
  • Community
  • ctrlc sync
  • ctrlc sync pipe
  • ctrlc apply
  • ctrlc api upsert version
  • Glossary & Reference
  • CEL Expression Language
  • RFC 0001: Scoped Versions

This view

  • Original page
  • New address

GeezerVison is showing docs.ctrlplane.dev — CEL Expression Language - docs

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

OperatorDescriptionExample
==Equalresource.kind == "KubernetesCluster"
!=Not equalresource.metadata["env"] != "dev"
<Less thanresource.metadata["priority"] < "5"
>Greater thanresource.metadata["replicas"] > "1"
<=Less or equalversion.metadata["build"] <= "100"
>=Greater or equalresource.metadata["tier"] >= "2"

​
Logical Operators

OperatorDescriptionExample
&&Logical ANDa == "x" && b == "y"
||Logical ORa == "x" || a == "y"
!Logical NOT!resource.metadata["deprecated"]

​
Arithmetic Operators

OperatorDescriptionExample
+Addition / Concatenation"prefix-" + resource.name
-Subtractionint(a) - int(b)
*Multiplicationint(a) * 2
/Divisionint(a) / 2
%Moduloint(a) % 2 == 0

​
Available Variables

​
Resource Context

When writing resource selectors:
VariableTypeDescription
resource.idstringUnique resource ID
resource.namestringResource display name
resource.kindstringResource type (e.g., KubernetesCluster)
resource.identifierstringExternal identifier
resource.versionstringResource version
resource.metadatamapKey-value metadata
resource.configmapResource configuration

​
Environment Context

When writing environment selectors:
VariableTypeDescription
environment.idstringEnvironment ID
environment.namestringEnvironment name
environment.metadatamapEnvironment metadata

​
Deployment Context

When writing deployment selectors:
VariableTypeDescription
deployment.idstringDeployment ID
deployment.namestringDeployment name
deployment.metadatamapDeployment metadata

​
Version Context

When writing version selectors:
VariableTypeDescription
version.idstringVersion ID
version.tagstringVersion tag
version.namestringVersion name
version.metadatamapVersion 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

​
in

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"

​
Performance Tips

​
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

ErrorCauseFix
no such keyAccessing missing map keyUse has() check
type mismatchComparing different typesUse type coercion
syntax errorInvalid CEL syntaxCheck quotes, brackets
undeclared referenceUnknown variableCheck 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:
  1. () - Grouping
  2. . [] - Member access
  3. - ! - Unary
  4. * / % - Multiplicative
  5. + - - Additive
  6. < <= > >= in - Relational
  7. == != - Equality
  8. && - Logical AND
  9. || - Logical OR
  10. ?: - Conditional

​
Next Steps

Selectors

Use CEL in selectors

Relationships

CEL in relationship rules

Policies

Target policies with CEL

Environments

Dynamic environment membership

Was this page helpful?

You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.