This commit adds support for native list variables and outputs, building
up on the previous change to state. Interpolation functions now return
native lists in preference to StringList.
List variables are defined like this:
variable "test" {
# This can also be inferred
type = "list"
default = ["Hello", "World"]
}
output "test_out" {
value = "${var.a_list}"
}
This results in the following state:
```
...
"outputs": {
"test_out": [
"hello",
"world"
]
},
...
```
And the result of terraform output is as follows:
```
$ terraform output
test_out = [
hello
world
]
```
Using the output name, an xargs-friendly representation is output:
```
$ terraform output test_out
hello
world
```
The output command also supports indexing into the list (with
appropriate range checking and no wrapping):
```
$ terraform output test_out 1
world
```
Along with maps, list outputs from one module may be passed as variables
into another, removing the need for the `join(",", var.list_as_string)`
and `split(",", var.list_as_string)` which was previously necessary in
Terraform configuration.
This commit also updates the tests and implementations of built-in
interpolation functions to take and return native lists where
appropriate.
A backwards compatibility note: previously the concat interpolation
function was capable of concatenating either strings or lists. The
strings use case was deprectated a long time ago but still remained.
Because we cannot return `ast.TypeAny` from an interpolation function,
this use case is no longer supported for strings - `concat` is only
capable of concatenating lists. This should not be a huge issue - the
type checker picks up incorrect parameters, and the native HIL string
concatenation - or the `join` function - can be used to replicate the
missing behaviour.
This changes the representation of maps in the interpolator from the
dotted flatmap form of a string variable named "var.variablename.key"
per map element to use native HIL maps instead.
This involves porting some of the interpolation functions in order to
keep the tests green, and adding support for map outputs.
There is one backwards incompatibility: as a result of an implementation
detail of maps, one could access an indexed map variable using the
syntax "${var.variablename.key}".
This is no longer possible - instead HIL native syntax -
"${var.variablename["key"]}" must be used. This was previously
documented, (though not heavily used) so it must be noted as a backward
compatibility issue for Terraform 0.7.
This function returns -1 for negative numbers, 0 for 0 and 1 for positive numbers.
Useful when you need to set a value for the first resource and a different value for the rest of the resources.
Example: `${element(split(",", var.r53_failover_policy), signum(count.index))}`
The render code path in `template_file` was doing unsynchronized access
to a shared mapping of functions in `config.Func`.
This caused a race condition that was most often triggered when a
`template_file` had a `count` of more than one, and expressed itself as
a panic in the plugin followed by a cascade of "unexpected EOF" errors
through the plugin system.
Here, we simply turn the FuncMap from shared state into a generated
value, which avoids the race. We do more re-initialization of the data
structure, but the performance implications are minimal, and we can
always revisit with a perf pass later now that the race is fixed.
These new functions allow Terraform to be used for network address space
planning tasks, and make it easier to produce reusable modules that
contain or depend on network infrastructure.
For example:
- cidrsubnet allows an aws_subnet to derive its
CIDR prefix from its parent aws_vpc.
- cidrhost allows a fixed IP address for a resource to be assigned within
an address range defined elsewhere.
- cidrnetmask provides the dotted-decimal form of a prefix length that is
accepted by some systems such as routing tables and static network
interface configuration files.
The bulk of the work here is done by an external library I authored called
go-cidr. It is MIT licensed and was implemented primarily for the purpose
of using it within Terraform. It has its own unit tests and so the unit
tests within this change focus on simple success cases and on the correct
handling of the various error cases.
There isn't any precedent for abbreviating words in the interpolation
function names, and it may not be clear to all users what "enc" and "dec"
are short for, so instead we'll prefer to spell out the whole words for
improved readability.
Had to handle a lot of implicit leaning on a few properties of the old
representation:
* Old representation allowed plain strings to be treated as lists
without problem (i.e. shoved into strings.Split), now strings need to
be checked whether they are a list before they are treated as one
(i.e. shoved into StringList(s).Slice()).
* Tested behavior of 0 and 1 length lists in formatlist() was a side
effect of the representation. Needs to be special cased now to
maintain the behavior.
* Found a pretty old context test failure that was wrong in several
different ways. It's covered by TestContext2Apply_multiVar so I
removed it.
This is the initial pure "all tests passing without a diff" stage. The
plan is to change the internal representation of StringList to include a
suffix delimiter, which will allow us to recognize empty and
single-element lists.
formatlist distributes formatting over lists.
See the docs for details.
As a colleague commented:
"It happens all the time that we want a set of
outputs, but in a slightly different way than
just simple joining or concatting."
formatlist (combined with join)
makes it easy to satisfy those needs.