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  ```