github.com/hashicorp/packer@v1.14.3/website/content/docs/templates/hcl_templates/expressions.mdx (about) 1 --- 2 page_title: HCL expressions reference 3 description: |- 4 HCL expressions provide access to data exported by data sources and transforms and combines the data into other values. Learn how to use HCL expressions in Packer templates. 5 --- 6 7 # HCL expressions reference 8 9 This topic provides reference information about expressions you can use in HCL templates for Packer. 10 11 ## Introduction 12 13 _Expressions_ are used to refer to or compute values within a configuration. 14 The simplest expressions are just literal values, like `"hello"` or `5`, but 15 HCL also allows more complex expressions such as references to data exported by 16 sources, arithmetic, conditional evaluation, and a number of built-in 17 functions. 18 19 Expressions can be used in a number of places in HCL, but some contexts limit 20 which expression constructs are allowed, such as requiring a literal value of a 21 particular type or forbidding. Each language feature's documentation describes 22 any restrictions it places on expressions. 23 24 The rest of this page describes all of the features of Packer's 25 expression syntax. 26 27 ## Types and Values 28 29 The result of an expression is a _value_. All values have a _type_, which 30 dictates where that value can be used and what transformations can be 31 applied to it. 32 33 HCL uses the following types for its values: 34 35 - `string`: a sequence of Unicode characters representing some text, like 36 `"hello"`. 37 - `number`: a numeric value. The `number` type can represent both whole 38 numbers like `15` and fractional values like `6.283185`. 39 - `bool`: either `true` or `false`. `bool` values can be used in conditional 40 logic. 41 - `list` (or `tuple`): a sequence of values, like 42 `["us-west-1a", "us-west-1c"]`. Elements in a list or tuple are identified by 43 consecutive whole numbers, starting with zero. 44 - `map` (or `object`): a group of values identified by named labels, like 45 `{name = "Mabel", age = 52}`. 46 47 Strings, numbers, and bools are sometimes called _primitive types._ 48 Lists/tuples and maps/objects are sometimes called _complex types,_ _structural 49 types,_ or _collection types._ 50 51 Finally, there is one special value that has _no_ type: 52 53 - `null`: a value that represents _absence_ or _omission._ If you set an 54 argument of a source or module to `null`, Packer behaves as though you 55 had completely omitted it — it will use the argument's default value if it has 56 one, or raise an error if the argument is mandatory. `null` is most useful in 57 conditional expressions, so you can dynamically omit an argument if a 58 condition isn't met. 59 60 ### Advanced Type Details 61 62 In most situations, lists and tuples behave identically, as do maps and objects. 63 Whenever the distinction isn't relevant, the Packer documentation uses each 64 pair of terms interchangeably (with a historical preference for "list" and 65 "map"). 66 67 However, plugin authors should understand the differences between these similar 68 types (and the related `set` type), since they offer different ways to restrict 69 the allowed values for input variables and source arguments. 70 71 ### Type Conversion 72 73 Expressions are most often used to set values for arguments. In these cases, 74 the argument has an expected type and the given expression must produce a value 75 of that type. 76 77 Where possible, Packer automatically converts values from one type to 78 another in order to produce the expected type. If this isn't possible, Packer 79 will produce a type mismatch error and you must update the configuration with a 80 more suitable expression. 81 82 Packer automatically converts number and bool values to strings when needed. 83 It also converts strings to numbers or bools, as long as the string contains a 84 valid representation of a number or bool value. 85 86 - `true` converts to `"true"`, and vice-versa 87 - `false` converts to `"false"`, and vice-versa 88 - `15` converts to `"15"`, and vice-versa 89 90 ## Literal Expressions 91 92 A _literal expression_ is an expression that directly represents a particular 93 constant value. Packer has a literal expression syntax for each of the value 94 types described above: 95 96 - Strings are usually represented by a double-quoted sequence of Unicode 97 characters, `"like this"`. There is also a "heredoc" syntax for more complex 98 strings. String literals are the most complex kind of literal expression in 99 Packer, and have additional documentation on this page: 100 - See [String Literals](#string-literals) below for information about escape 101 sequences and the heredoc syntax. 102 - See [String Templates](#string-templates) below for information about 103 interpolation and template directives. 104 - Numbers are represented by unquoted sequences of digits with or without a 105 decimal point, like `15` or `6.283185`. 106 - Bools are represented by the unquoted symbols `true` and `false`. 107 - The null value is represented by the unquoted symbol `null`. 108 - Lists/tuples are represented by a pair of square brackets containing a 109 comma-separated sequence of values, like `["a", 15, true]`. 110 111 List literals can be split into multiple lines for readability, but always 112 require a comma between values. A comma after the final value is allowed, 113 but not required. Values in a list can be arbitrary expressions. 114 115 - Maps/objects are represented by a pair of curly braces containing a series of 116 `<KEY> = <VALUE>` pairs: 117 118 ```hcl 119 { 120 name = "John" 121 age = 52 122 } 123 ``` 124 125 Key/value pairs can be separated by either a comma or a line break. Values 126 can be arbitrary expressions. Keys are strings; they can be left unquoted if 127 they are a valid [identifier](/packer/docs/templates/hcl_templates/syntax#identifiers), but must be quoted 128 otherwise. You can use a non-literal expression as a key by wrapping it in 129 parentheses, like `(var.business_unit_tag_name) = "SRE"`. 130 131 ## References to Named Values 132 133 Packer makes one named values available. 134 135 The following named values are available: 136 137 - `source.<SOURCE TYPE>.<NAME>` is an object representing a 138 [source](/packer/docs/templates/hcl_templates/blocks/source) of the given type 139 and name. 140 141 ### Available Functions 142 143 For a full list of available functions, see [the function 144 reference](/packer/docs/templates/hcl_templates/functions). 145 146 ## Conditional Expressions 147 148 A conditional expression uses the value of a boolean expression to select one of 149 two values. This is a compact way to express `if-then-else` logic inside an 150 expression. 151 152 The syntax for a conditional expression is: 153 154 ```hcl 155 condition ? true_val : false_val 156 ``` 157 158 If `condition` is `true`, the expression returns `true_val`. If `condition` is 159 `false`, it returns `false_val`. The `true_val` and `false_val` arguments must 160 be of compatible types. 161 162 ### Examples 163 164 Here are some examples of how to use conditional expressions. 165 166 1. Setting a Default Value 167 168 You can use a conditional to provide a default value for a variable that 169 can also be customized. 170 171 ```hcl 172 locals { 173 # Set the region to the value of var.region if it is not empty. 174 # Otherwise, use a default value. 175 region = var.region != "" ? var.region : "us-east-1" 176 } 177 ``` 178 179 2. Dynamically Omitting an Argument 180 181 You can use a `null` value to dynamically omit an argument from a source. 182 This is a common pattern to effectively "turn off" or prevent an argument 183 from being set. 184 185 ```hcl 186 variable "use_http" { 187 type = bool 188 description = "Whether to use HTTP for file transfer." 189 default = true 190 } 191 192 source "example" "foo" { 193 # The http_directory argument is only set if var.use_http is true. 194 # If false, http_directory will be unset. 195 http_directory = var.use_http ? "/path/to/files" : null 196 } 197 ``` 198 199 This can also be used to set one of two mutually exclusive arguments: 200 201 ```hcl 202 source "builder" "example" { 203 # If var.use_http is true, http_content is set and cd_content is null. 204 # If var.use_http is false, http_content is null and cd_content is set. 205 http_content = var.use_http ? local.http_files : null 206 cd_content = !var.use_http ? local.cd_files : null 207 } 208 ``` 209 210 ### Readability and Recommended Practices 211 212 While powerful, conditional expressions can lead to complex or hard-to-read 213 configurations if not used carefully. 214 215 * **Prioritize Clarity:** When a conditional expression becomes very long or 216 involves multiple nested conditions, consider breaking it down. 217 218 * **Leverage `locals` for Complexity:** For more intricate conditional logic, 219 define the result in a `local` variable. This improves readability in the 220 main `source` or `provisioner` blocks where the `local` is consumed. 221 222 **Example:** 223 224 ```hcl 225 locals { 226 # Determine the kickstart file based on the build environment. 227 kickstart_config_path = var.environment == "production" ? 228 "config/prod-ks.cfg" : 229 (var.environment == "staging" ? 230 "config/stage-ks.cfg" : 231 "config/dev-ks.cfg") 232 } 233 234 source "builder" "example" { 235 # ... 236 # Use the pre-determined kickstart path. 237 http_content = file(local.kickstart_config_path) 238 # ... 239 } 240 ``` 241 242 * **Use `null` to Omit Arguments:** As demonstrated in the examples, 243 using `null` is the idiomatic way to prevent an argument from being set or 244 to effectively "turn off" a setting based on a condition. 245 246 ## `for` Expressions 247 248 A _`for` expression_ creates a complex type value by transforming 249 another complex type value. Each element in the input value 250 can correspond to either one or zero values in the result, and an arbitrary 251 expression can be used to transform each input element into an output element. 252 253 For example, if `var.list` is a list of strings, then the following expression 254 produces a list of strings with all-uppercase letters: 255 256 ```hcl 257 [for s in var.list : upper(s)] 258 ``` 259 260 This `for` expression iterates over each element of `var.list`, and then 261 evaluates the expression `upper(s)` with `s` set to each respective element. 262 It then builds a new tuple value with all of the results of executing that 263 expression in the same order. 264 265 The type of brackets around the `for` expression decide what type of result 266 it produces. The above example uses `[` and `]`, which produces a tuple. If 267 `{` and `}` are used instead, the result is an object, and two result 268 expressions must be provided separated by the `=>` symbol: 269 270 ```hcl 271 {for s in var.list : s => upper(s)} 272 ``` 273 274 This expression produces an object whose attributes are the original elements 275 from `var.list` and their corresponding values are the uppercase versions. 276 277 A `for` expression can also include an optional `if` clause to filter elements 278 from the source collection, which can produce a value with fewer elements than 279 the source: 280 281 ```text 282 [for s in var.list : upper(s) if s != ""] 283 ``` 284 285 The source value can also be an object or map value, in which case two 286 temporary variable names can be provided to access the keys and values 287 respectively: 288 289 ```text 290 [for k, v in var.map : length(k) + length(v)] 291 ``` 292 293 Finally, if the result type is an object (using `{` and `}` delimiters) then 294 the value result expression can be followed by the `...` symbol to group 295 together results that have a common key: 296 297 ```text 298 {for s in var.list : substr(s, 0, 1) => s... if s != ""} 299 ``` 300 301 ## Splat Expressions 302 303 A _splat expression_ provides a more concise way to express a common operation 304 that could otherwise be performed with a `for` expression. 305 306 If `var.list` is a list of objects that all have an attribute `id`, then a list 307 of the IDs could be produced with the following `for` expression: 308 309 ```hcl 310 [for o in var.list : o.id] 311 ``` 312 313 This is equivalent to the following _splat expression:_ 314 315 ```hcl 316 var.list[*].id 317 ``` 318 319 The special `[*]` symbol iterates over all of the elements of the list given to 320 its left and accesses from each one the attribute name given on its right. A 321 splat expression can also be used to access attributes and indexes from lists 322 of complex types by extending the sequence of operations to the right of the 323 symbol: 324 325 ```hcl 326 var.list[*].interfaces[0].name 327 ``` 328 329 The above expression is equivalent to the following `for` expression: 330 331 ```hcl 332 [for o in var.list : o.interfaces[0].name] 333 ``` 334 335 Splat expressions are for lists only (and thus cannot be used [to reference 336 resources created with 337 `for_each`](/terraform/docs/configuration/resources#referring-to-instances), which 338 are represented as maps). However, if a splat expression is applied to a value 339 that is _not_ a list or tuple then the value is automatically wrapped in a 340 single-element list before processing. 341 342 For example, `var.single_object[*].id` is equivalent to 343 `[var.single_object][*].id`, or effectively `[var.single_object.id]`. This 344 behavior is not interesting in most cases, but it is particularly useful when 345 referring to resources that may or may not have `count` set, and thus may or 346 may not produce a tuple value: 347 348 ```hcl 349 aws_instance.example[*].id 350 ``` 351 352 The above will produce a list of IDs whether `aws_instance.example` has `count` 353 set or not, avoiding the need to revise various other expressions in the 354 configuration when a particular resource switches to and from having `count` 355 set. 356 357 ## `dynamic` blocks 358 359 Within top-level block constructs like [source](/packer/docs/templates/hcl_templates/blocks/source), expressions 360 can usually be used only when assigning a value to an argument using the `name = expression` or `key = expression` form. 361 This covers many uses, but some source types include repeatable _nested blocks_ in their arguments, which do not accept expressions: 362 363 ```hcl 364 source "amazon-ebs" "example" { 365 name = "pkr-test-name" # can use expressions here 366 367 tag { 368 # but the "tag" block is always a literal block 369 } 370 } 371 ``` 372 373 You can dynamically construct repeatable nested blocks like `tag` using a 374 special `dynamic` block type, which is supported in top-level block constructs, example: 375 376 ```hcl 377 locals { 378 standard_tags = { 379 Component = "user-service" 380 Environment = "production" 381 } 382 } 383 384 source "amazon-ebs" "example" { 385 # ... 386 387 tag { 388 key = "Name" 389 value = "example-asg-name" 390 } 391 392 dynamic "tag" { 393 for_each = local.standard_tags 394 395 content { 396 key = tag.key 397 value = tag.value 398 } 399 } 400 } 401 ``` 402 403 A `dynamic` block acts much like a `for` expression, but produces nested blocks 404 instead of a complex typed value. It iterates over a given complex value, and 405 generates a nested block for each element of that complex value. 406 407 - The label of the dynamic block (`"tag"` in the example above) specifies 408 what kind of nested block to generate. 409 - The `for_each` argument provides the complex value to iterate over. 410 - The `iterator` argument (optional) sets the name of a temporary variable 411 that represents the current element of the complex value. If omitted, the name 412 of the variable defaults to the label of the `dynamic` block (`"tag"` in 413 the example above). 414 - The `labels` argument (optional) is a list of strings that specifies the block 415 labels, in order, to use for each generated block. You can use the temporary 416 iterator variable in this value. 417 - The nested `content` block defines the body of each generated block. You can 418 use the temporary iterator variable inside this block. 419 420 Since the `for_each` argument accepts any collection or structural value, 421 you can use a `for` expression or splat expression to transform an existing 422 collection. 423 424 The iterator object (`tag` in the example above) has two attributes: 425 426 - `key` is the map key or list element index for the current element. If the 427 `for_each` expression produces a _set_ value then `key` is identical to 428 `value` and should not be used. 429 - `value` is the value of the current element. 430 431 A `dynamic` block can only generate arguments for nested blocks that belong to 432 the source type, data source, or provisioner being configured. 433 434 The `for_each` value must be a map or set with one element per desired nested 435 block. If you need to declare resource instances based on a nested data 436 structure or combinations of elements from multiple data structures you can use 437 expressions and functions to derive a suitable value. For some common examples 438 of such situations, see the 439 [`flatten`](/packer/docs/templates/hcl_templates/functions/collection/flatten) and 440 [`setproduct`](/packer/docs/templates/hcl_templates/functions/collection/setproduct) 441 functions. 442 443 ### Best Practices for `dynamic` Blocks 444 445 Overuse of `dynamic` blocks can make configuration hard to read and maintain, 446 so we recommend using them only when you need to hide details in order to build 447 a clean user interface for a re-usable code. Always write nested blocks out 448 literally where possible. 449 450 ## String Literals 451 452 HCL has two different syntaxes for string literals. The 453 most common is to delimit the string with quote characters (`"`), like 454 `"hello"`. In quoted strings, the backslash character serves as an escape 455 sequence, with the following characters selecting the escape behavior: 456 457 | Sequence | Replacement | 458 | ------------ | ----------------------------------------------------------------------------- | 459 | `\n` | Newline | 460 | `\r` | Carriage Return | 461 | `\t` | Tab | 462 | `\"` | Literal quote (without terminating the string) | 463 | `\\` | Literal backslash | 464 | `\uNNNN` | Unicode character from the basic multilingual plane (NNNN is four hex digits) | 465 | `\UNNNNNNNN` | Unicode character from supplementary planes (NNNNNNNN is eight hex digits) | 466 467 The alternative syntax for string literals is the so-called Here Documents or 468 "heredoc" style, inspired by Unix shell languages. This style allows multi-line 469 strings to be expressed more clearly by using a custom delimiter word on a line 470 of its own to close the string: 471 472 ```hcl 473 <<EOF 474 hello 475 world 476 EOF 477 ``` 478 479 The `<<` marker followed by any identifier at the end of a line introduces the 480 sequence. Packer then processes the following lines until it finds one that 481 consists entirely of the identifier given in the introducer. In the above 482 example, `EOF` is the identifier selected. Any identifier is allowed, but 483 conventionally this identifier is in all-uppercase and begins with `EO`, meaning 484 "end of". `EOF` in this case stands for "end of text". 485 486 The "heredoc" form shown above requires that the lines following be flush with 487 the left margin, which can be awkward when an expression is inside an indented 488 block: 489 490 ```hcl 491 block { 492 value = <<EOF 493 hello 494 world 495 EOF 496 } 497 ``` 498 499 To improve on this, Packer also accepts an _indented_ heredoc string variant 500 that is introduced by the `<<-` sequence: 501 502 ```hcl 503 block { 504 value = <<-EOF 505 hello 506 world 507 EOF 508 } 509 ``` 510 511 In this case, Packer analyses the lines in the sequence to find the one 512 with the smallest number of leading spaces, and then trims that many spaces 513 from the beginning of all of the lines, leading to the following result: 514 515 ```text 516 hello 517 world 518 ``` 519 520 Backslash sequences are not interpreted in a heredoc string expression. 521 Instead, the backslash character is interpreted literally. 522 523 In both quoted and heredoc string expressions, Packer supports template 524 sequences that begin with `${` and `%{`. These are described in more detail 525 in the following section. To include these sequences _literally_ without 526 beginning a template sequence, double the leading character: `$${` or `%%{`. 527 528 ## String Templates 529 530 Within quoted and heredoc string expressions, the sequences `${` and `%{` begin 531 _template sequences_. Templates let you directly embed expressions into a string 532 literal, to dynamically construct strings from other values. 533 534 The following example demonstrates how a template sequence can be used to embed 535 the value of a variable into a string that can be used as script content: 536 537 ```hcl 538 locals { 539 packages = ["git", "curl", "vim"] 540 541 install_packages = <<-EOF 542 #!/bin/bash 543 if [ ${length(local.packages)} -eq 0 ]; then 544 echo "No packages to install." 545 exit 1 546 fi 547 apt-get update 548 %{ for package in local.packages ~} 549 apt-get install -y ${package} 550 %{ endfor ~} 551 EOF 552 } 553 554 source "amazon-ebs" "example" { 555 # ... 556 } 557 558 build { 559 sources = ["source.amazon-ebs.example"] 560 561 provisioner "shell" { 562 inline = [local.install_packages] 563 } 564 } 565 ``` 566 567 This can be tested using the `packer console` command: 568 569 ```shell 570 $ packer source.pkr.hcl 571 572 > local.install_packages 573 574 > #!/bin/bash 575 if [ 3 -eq 0 ]; then 576 echo "No packages to install." 577 exit 1 578 fi 579 apt-get update 580 apt-get install -y git 581 apt-get install -y curl 582 apt-get install -y vim 583 ```