CEL Expressions
expr
expressions use the Common Expression Language (CEL)
The CEL playground lets you test CEL expressions
---
apiVersion: canaries.flanksource.com/v1
kind: Canary
metadata:
name: currency-converter-display-cel
spec:
http:
- name: USD
url: https://api.frankfurter.app/latest?from=USD&to=GBP,EUR,ILS,ZAR
display:
expr: "'$1 = €' + string(json.rates.EUR) + ', £' + string(json.rates.GBP) + ', ₪' + string(json.rates.ILS)"
Values in CEL represent any of the following:
Type | Description |
---|---|
int | 64-bit signed integers |
uint | 64-bit unsigned integers |
double | 64-bit IEEE floating-point numbers |
bool | Booleans (true or false ) |
string | Strings of Unicode code points |
bytes | Byte sequences |
list | Lists of values |
map | Associative arrays with int , uint , bool , or string keys |
null_type | The value null |
message names | Protocol buffer messages |
type | Values representing the types in the first column |
Standard Operators
Arithmetic Operators
Operator | Description | Example |
---|---|---|
+ | Addition (also string/list concatenation) | 2 + 3 → 5 "hello" + " world" → "hello world" [1, 2] + [3, 4] → [1, 2, 3, 4] |
- | Subtraction (also negation) | 5 - 3 → 2 -5 → -5 |
* | Multiplication | 3 * 4 → 12 |
/ | Division | 10 / 2 → 5 |
% | Remainder (modulo) | 10 % 3 → 1 |
Comparison Operators
Operator | Description | Example |
---|---|---|
== | Equal | 5 == 5 → true |
!= | Not equal | 5 != 3 → true |
< | Less than | 3 < 5 → true |
<= | Less than or equal | 5 <= 5 → true |
> | Greater than | 5 > 3 → true |
>= | Greater than or equal | 5 >= 5 → true |
Logical Operators
Operator | Description | Example |
---|---|---|
&& | Logical AND | true && false → false |
|| | Logical OR | true || false → true |
! | Logical NOT | !true → false |
? : | Ternary conditional | true ? "yes" : "no" → "yes" |
Type Conversion Functions
Function | Description | Example |
---|---|---|
bool() | Convert to boolean | bool("true") → true |
bytes() | Convert to bytes | bytes("hello") → b'hello' |
double() | Convert to double | double(5) → 5.0 |
duration() | Convert to duration | duration("1h") → 1 hour duration |
int() | Convert to integer | int(5.7) → 5 |
string() | Convert to string | string(123) → "123" |
timestamp() | Convert to timestamp | timestamp("2023-01-01T00:00:00Z") |
uint() | Convert to unsigned integer | uint(5) → 5u |
type() | Get the type of a value | type(5) → int |
dyn() | Create a dynamic value | dyn({"key": "value"}) |
Built-in Functions
Type Checking
// Get the type of any value
type(5) // "int"
type("hello") // "string"
type([1, 2, 3]) // "list"
type({"key": "value"}) // "map"
Handling null types and missing keys
When dealing with CEL objects, we might get errors where a key doesn't exist or if you're chaining keys, then one of the keys in the middle is missing.
// Assume we have an obj with value: {'a': {'b': 'c'}}
o.a.b => c
o.a.d // Error, attribute 'd' doesn't exist
o.a.?d.orValue('fallback value') => 'fallback value'
You can read more about or and orValue below.
matchQuery
matchQuery
matches a given resource against a search query.
Syntax:
matchQuery(r, s)
// Where
// r = resource
// s = search query
Example:
matchQuery(.config, "type=Kubernetes::Pod")
matchQuery(.config, "type=Kubernetes::Pod tags.cluster=homelab")
matchLabel
matchLabel
matches a map's key against one or more patterns. It's particularly useful for matching against labels in Kubernetes objects or configuration items.
Syntax:
matchLabel(labels, key, patterns)
// Where
// labels = map of labels
// key = the label key to check
// patterns = comma-separated patterns to match against
Pattern Syntax:
- Use
*
for wildcards (e.g.,us-*
matchesus-east-1
,us-west-2
) - Use
!
for exclusion (e.g.,!production
matches any value exceptproduction
) - Use
!*
to match when the label doesn't exist - Multiple patterns are evaluated as OR conditions
Example:
// Match labels with wildcards
matchLabel(config.labels, "region", "us-*") // true if region starts with "us-"
matchLabel(config.labels, "env", "prod,staging") // true if env is "prod" OR "staging"
// Exclusion patterns
matchLabel(config.labels, "env", "!production") // true if env is NOT "production"
matchLabel(config.labels, "optional", "!*") // true if "optional" label doesn't exist
// Complex matching
matchLabel(config.tags, "cluster", "*-prod,*-staging") // true if cluster ends with "-prod" OR "-staging"
aws
aws.arnToMap
Takes in an AWS ARN, parses it, and returns a map.
aws.arnToMap("arn:aws:sns:eu-west-1:123:MMS-Topic") //
// map[string]string{
// "service": string,
// "region": string,
// "account": string,
// "resource": string,
// }
aws.fromAWSMap
aws.fromAWSMap
takes a list of map[string]string
and merges them into a single map. The input map has the field "Name".
aws.fromAWSMap(x).hello" == "world" // `true`
// Where
// x = [
// { Name: 'hello', Value: 'world' },
// { Name: 'John', Value: 'Doe' },
// ];
base64
base64.encode
base64.encode
encodes the given byte slice to a Base64 encoded string.
base64.decode("aGVsbG8=") // return b'hello'
base64.decode
base64.decode
decodes the given base64 encoded string back to its original form.
base64.decode("aGVsbG8=") // return b'hello'
collections
.keys
The keys
method on a map returns a list of keys.
Syntax:
e.keys()
// Where:
// `e` is a map .
Examples:
{"first": "John", "last": "Doe"}.keys() // ["first", "last"]
.merge
The merge
method on a map takes a second map to merge.
Syntax:
e.merge(x)
// Where:
// `e` is the map you want to merge to.
// `x` is the second map to merge from.
Examples:
{"first": "John"}.merge({"last": "Doe"}) // {"first": "John", "last": "Doe"}
.omit
The omit
method on a map takes a list of keys to remove.
Syntax:
e.omit(x)
// Where:
// `e` is a list .
// `x` is a list of keys to omit.
Examples:
{"first": "John", "last": "Doe"}.omit(["first"]) // {"last": "Doe"}
.sort
The sort
method on a list returns a sorted list.
Syntax:
e.sort()
// Where:
// `e` is a list .
Examples:
[3, 2, 1].sort() // [1, 2, 3]
['c', 'b', 'a'].sort() // ['a', 'b', 'c']