github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/website/content/docs/job-specification/hcl2/expressions.mdx (about)

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