github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/website/content/docs/job-specification/hcl2/expressions.mdx (about) 1 --- 2 layout: docs 3 page_title: Expressions - Configuration Language 4 description: |- 5 HCL allows the use of expressions to access data exported 6 by sources and to transform and combine that data to produce other values. 7 --- 8 9 # Expressions 10 11 _Expressions_ are used to refer to or compute values within a configuration. 12 The simplest expressions are just literal values, like `"hello"` or `5`, but 13 HCL also allows more complex expressions such as arithmetic, conditional 14 evaluation, and a number of built-in functions. 15 16 Expressions can be used in a number of places in HCL, particularly as attribute 17 values. Attribute value expressions must adhere to the attribute type. Block 18 labels must be string literals without any interpolation. Each language 19 feature's documentation describes any restrictions it places on expressions. 20 21 The rest of this page describes all of the features of Nomad's 22 expression syntax. 23 24 ## Types and Values 25 26 The result of an expression is a _value_. All values have a _type_, which 27 dictates where that value can be used and what transformations can be 28 applied to it. 29 30 HCL uses the following types for its values: 31 32 - `string`: a sequence of Unicode characters representing some text, like 33 `"hello"`. 34 - `number`: a numeric value. The `number` type can represent both whole 35 numbers like `15` and fractional values like `6.283185`. 36 - `bool`: either `true` or `false`. `bool` values can be used in conditional 37 logic. 38 - `list` (or `tuple`): a sequence of values, like 39 `["us-west-1a", "us-west-1c"]`. Elements in a list or tuple are identified by 40 consecutive whole numbers, starting with zero. 41 - `map` (or `object`): a group of values identified by named labels, like 42 `{name = "Mabel", age = 52}`. 43 44 Strings, numbers, and bools are sometimes called _primitive types._ 45 Lists/tuples and maps/objects are sometimes called _complex types,_ _structural 46 types,_ or _collection types._ 47 48 Finally, there is one special value that has _no_ type: 49 50 - `null`: a value that represents _absence_ or _omission._ If you set an 51 argument to `null`, Nomad behaves as though you 52 had completely omitted it — it will use the argument's default value if it has 53 one, or raise an error if the argument is mandatory. `null` is most useful in 54 conditional expressions, so you can dynamically omit an argument if a 55 condition isn't met. 56 57 ### Advanced Type Details 58 59 In most situations, lists and tuples behave identically, as do maps and objects. 60 Whenever the distinction isn't relevant, the Nomad documentation uses each 61 pair of terms interchangeably (with a historical preference for "list" and 62 "map"). 63 64 ### Type Conversion 65 66 Expressions are most often used to set values for arguments. In these cases, 67 the argument has an expected type and the given expression must produce a value 68 of that type. 69 70 Where possible, Nomad automatically converts values from one type to 71 another in order to produce the expected type. If this isn't possible, Nomad 72 will produce a type mismatch error and you must update the configuration with a 73 more suitable expression. 74 75 Nomad automatically converts number and bool values to strings when needed. 76 It also converts strings to numbers or bools, as long as the string contains a 77 valid representation of a number or bool value. 78 79 - `true` converts to `"true"`, and vice-versa 80 - `false` converts to `"false"`, and vice-versa 81 - `15` converts to `"15"`, and vice-versa 82 83 ## Literal Expressions 84 85 A _literal expression_ is an expression that directly represents a particular 86 constant value. Nomad has a literal expression syntax for each of the value 87 types described above: 88 89 - Strings are usually represented by a double-quoted sequence of Unicode 90 characters, `"like this"`. There is also a "heredoc" syntax for more complex 91 strings. String literals are the most complex kind of literal expression in 92 Nomad, and have additional documentation on this page: 93 - See [String Literals](#string-literals) below for information about escape 94 sequences and the heredoc syntax. 95 - See [String Templates](#string-templates) below for information about 96 interpolation and template directives. 97 - Numbers are represented by unquoted sequences of digits with or without a 98 decimal point, like `15` or `6.283185`. 99 - Bools are represented by the unquoted symbols `true` and `false`. 100 - The null value is represented by the unquoted symbol `null`. 101 - Lists/tuples are represented by a pair of square brackets containing a 102 comma-separated sequence of values, like `["a", 15, true]`. 103 104 List literals can be split into multiple lines for readability, but always 105 require a comma between values. A comma after the final value is allowed, 106 but not required. Values in a list can be arbitrary expressions. 107 108 - Maps/objects are represented by a pair of curly braces containing a series of 109 `<KEY> = <VALUE>` pairs: 110 111 ```hcl 112 { 113 name = "John" 114 age = 52 115 } 116 ``` 117 118 Key/value pairs can be separated by either a comma or a line break. Values 119 can be arbitrary expressions. Keys are strings; they can be left unquoted if 120 they are a valid [identifier](/docs/job-specification/hcl2/syntax#identifiers), but must be quoted 121 otherwise. You can use a non-literal expression as a key by wrapping it in 122 parentheses, like `(var.business_unit_tag_name) = "SRE"`. 123 124 ### Available Functions 125 126 For a full list of available functions, see [the function 127 reference](/docs/job-specification/hcl2/functions). 128 129 ## `for` Expressions 130 131 A _`for` expression_ creates a complex type value by transforming 132 another complex type value. Each element in the input value 133 can correspond to either one or zero values in the result, and an arbitrary 134 expression can be used to transform each input element into an output element. 135 136 For example, if `var.list` is a list of strings, then the following expression 137 produces a list of strings with all-uppercase letters: 138 139 ```hcl 140 [for s in var.list : upper(s)] 141 ``` 142 143 This `for` expression iterates over each element of `var.list`, and then 144 evaluates the expression `upper(s)` with `s` set to each respective element. 145 It then builds a new tuple value with all of the results of executing that 146 expression in the same order. 147 148 The type of brackets around the `for` expression decide what type of result 149 it produces. The above example uses `[` and `]`, which produces a tuple. If 150 `{` and `}` are used instead, the result is an object, and two result 151 expressions must be provided separated by the `=>` symbol: 152 153 ```hcl 154 {for s in var.list : s => upper(s)} 155 ``` 156 157 This expression produces an object whose attributes are the original elements 158 from `var.list` and their corresponding values are the uppercase versions. 159 160 A `for` expression can also include an optional `if` clause to filter elements 161 from the source collection, which can produce a value with fewer elements than 162 the source: 163 164 ```text 165 [for s in var.list : upper(s) if s != ""] 166 ``` 167 168 The source value can also be an object or map value, in which case two 169 temporary variable names can be provided to access the keys and values 170 respectively: 171 172 ```text 173 [for k, v in var.map : length(k) + length(v)] 174 ``` 175 176 Finally, if the result type is an object (using `{` and `}` delimiters) then 177 the value result expression can be followed by the `...` symbol to group 178 together results that have a common key: 179 180 ```text 181 {for s in var.list : substr(s, 0, 1) => s... if s != ""} 182 ``` 183 184 <!--- 185 ## TODO: revamp this section 186 187 ## Splat Expressions 188 189 A _splat expression_ provides a more concise way to express a common operation 190 that could otherwise be performed with a `for` expression. 191 192 If `var.list` is a list of objects that all have an attribute `id`, then a list 193 of the ids could be produced with the following `for` expression: 194 195 ```hcl 196 [for o in var.list : o.id] 197 ``` 198 199 This is equivalent to the following _splat expression:_ 200 201 ```hcl 202 var.list[*].id 203 ``` 204 205 The special `[*]` symbol iterates over all of the elements of the list given to 206 its left and accesses from each one the attribute name given on its right. A 207 splat expression can also be used to access attributes and indexes from lists 208 of complex types by extending the sequence of operations to the right of the 209 symbol: 210 211 ```hcl 212 var.list[*].interfaces[0].name 213 ``` 214 215 The above expression is equivalent to the following `for` expression: 216 217 ```hcl 218 [for o in var.list : o.interfaces[0].name] 219 ``` 220 221 Splat expressions are for lists only (and thus cannot be used [to reference 222 resources created with 223 `for_each`](https://www.terraform.io/docs/configuration/resources.html#referring-to-instances), which 224 are represented as maps). However, if a splat expression is applied to a value 225 that is _not_ a list or tuple then the value is automatically wrapped in a 226 single-element list before processing. 227 228 For example, `var.single_object[*].id` is equivalent to 229 `[var.single_object][*].id`, or effectively `[var.single_object.id]`. This 230 behavior is not interesting in most cases, but it is particularly useful when 231 referring to resources that may or may not have `count` set, and thus may or 232 may not produce a tuple value: 233 234 ```hcl 235 aws_instance.example[*].id 236 ``` 237 238 The above will produce a list of ids whether `aws_instance.example` has `count` 239 set or not, avoiding the need to revise various other expressions in the 240 configuration when a particular resource switches to and from having `count` 241 set. 242 243 ---> 244 245 ## `dynamic` blocks 246 247 Within top-level block constructs like sources, expressions can usually be used 248 only when assigning a value to an argument using the `name = expression` or 249 `key = expression` form. This covers many uses, but some source types include 250 repeatable _nested blocks_ in their arguments, which do not accept expressions: 251 252 ```hcl 253 network { 254 mode = "host" # can use expressions here 255 256 port "label" { 257 # but the "port" block is always a literal block 258 } 259 } 260 ``` 261 262 You can dynamically construct repeatable nested blocks like `port` using a 263 special `dynamic` block type, which is supported anywhere, example: 264 265 ```hcl 266 locals { 267 ports = [ 268 { 269 port_label = "api" 270 port = 80 271 }, 272 { 273 port_label = "ui" 274 port = 8080 275 } 276 ] 277 } 278 279 job "example" { 280 datacenters = ["dc1"] 281 282 group "cache" { 283 network { 284 285 mode = "host" 286 287 dynamic "port" { 288 for_each = local.ports 289 labels = [port.value.port_label] 290 291 content { 292 to = port.value.port 293 } 294 } 295 } 296 ... 297 ``` 298 299 A `dynamic` block acts much like a `for` expression, but produces nested blocks 300 instead of a complex typed value. It iterates over a given complex value, and 301 generates a nested block for each element of that complex value. 302 303 - The label of the dynamic block (`"port"` in the example above) specifies 304 what kind of nested block to generate. 305 - The `for_each` argument provides the complex value to iterate over. 306 - The `iterator` argument (optional) sets the name of a temporary variable 307 that represents the current element of the complex value. If omitted, the name 308 of the variable defaults to the label of the `dynamic` block (`"port"` in 309 the example above). 310 - The `labels` argument (optional) is a list of strings that specifies the block 311 labels, in order, to use for each generated block. You can use the temporary 312 iterator variable in this value. Nomad currently only has blocks that support 313 a single label such as `port`. 314 - The nested `content` block defines the body of each generated block. You can 315 use the temporary iterator variable inside this block. 316 317 Since the `for_each` argument accepts any collection or structural value, 318 you can use a `for` expression or splat expression to transform an existing 319 collection. 320 321 The iterator object (`port` in the example above) has two attributes: 322 323 - `key` is the map key or list element index for the current element. If the 324 `for_each` expression produces a _set_ value then `key` is identical to 325 `value` and should not be used. 326 - `value` is the value of the current element. 327 328 The `for_each` value must be a map or set with one element per desired nested 329 block. If you need to declare resource instances based on a nested data 330 structure or combinations of elements from multiple data structures you can use 331 expressions and functions to derive a suitable value. For some common examples 332 of such situations, see the 333 [`flatten`](/docs/job-specification/hcl2/functions/collection/flatten) and 334 [`setproduct`](/docs/job-specification/hcl2/functions/collection/setproduct) 335 functions. 336 337 ### Best Practices for `dynamic` Blocks 338 339 Overuse of `dynamic` blocks can make configuration hard to read and maintain, 340 so we recommend using them only when you need to hide details in order to build 341 a clean user interface for a re-usable code. Always write nested blocks out 342 literally where possible. 343 344 ## String Literals 345 346 HCL has two different syntaxes for string literals. The 347 most common is to delimit the string with quote characters (`"`), like 348 `"hello"`. In quoted strings, the backslash character serves as an escape 349 sequence, with the following characters selecting the escape behavior: 350 351 | Sequence | Replacement | 352 | ------------ | ----------------------------------------------------------------------------- | 353 | `\n` | Newline | 354 | `\r` | Carriage Return | 355 | `\t` | Tab | 356 | `\"` | Literal quote (without terminating the string) | 357 | `\\` | Literal backslash | 358 | `\uNNNN` | Unicode character from the basic multilingual plane (NNNN is four hex digits) | 359 | `\UNNNNNNNN` | Unicode character from supplementary planes (NNNNNNNN is eight hex digits) | 360 361 The alternative syntax for string literals is the so-called Here Documents or 362 "heredoc" style, inspired by Unix shell languages. This style allows multi-line 363 strings to be expressed more clearly by using a custom delimiter word on a line 364 of its own to close the string: 365 366 ```hcl 367 <<EOF 368 hello 369 world 370 EOF 371 ``` 372 373 The `<<` marker followed by any identifier at the end of a line introduces the 374 sequence. Nomad then processes the following lines until it finds one that 375 consists entirely of the identifier given in the introducer. In the above 376 example, `EOF` is the identifier selected. Any identifier is allowed, but 377 conventionally this identifier is in all-uppercase and begins with `EO`, meaning 378 "end of". `EOF` in this case stands for "end of text". 379 380 The "heredoc" form shown above requires that the lines following be flush with 381 the left margin, which can be awkward when an expression is inside an indented 382 block: 383 384 ```hcl 385 block { 386 value = <<EOF 387 hello 388 world 389 EOF 390 } 391 ``` 392 393 To improve on this, Nomad also accepts an _indented_ heredoc string variant 394 that is introduced by the `<<-` sequence: 395 396 ```hcl 397 block { 398 value = <<-EOF 399 hello 400 world 401 EOF 402 } 403 ``` 404 405 In this case, Nomad analyses the lines in the sequence to find the one 406 with the smallest number of leading spaces, and then trims that many spaces 407 from the beginning of all of the lines, leading to the following result: 408 409 ```text 410 hello 411 world 412 ``` 413 414 Backslash sequences are not interpreted in a heredoc string expression. 415 Instead, the backslash character is interpreted literally. 416 417 In both quoted and heredoc string expressions, Nomad supports template 418 sequences that begin with `${` and `%{`. These are described in more detail 419 in the following section. To include these sequences _literally_ without 420 beginning a template sequence, double the leading character: `$${` or `%%{`. 421 422 ## String Templates 423 424 Within quoted and heredoc string expressions, the sequences `${` and `%{` begin 425 _template sequences_. Templates let you directly embed expressions into a string 426 literal, to dynamically construct strings from other values.