Commit Graph

197 Commits

Author SHA1 Message Date
Martin Atkins f09b090d97 lang: Allow "resource." prefix as another way to refer to resources
The current way to refer to a managed resource is to use its resource type
name as a top-level symbol in the reference. This is convenient and makes
sense given that managed resources are the primary kind of object in
Terraform.

However, it does mean that an externally-extensible namespace (the set
of all possible resource type names) overlaps with a reserved word
namespace (the special prefixes like "path", "var", etc), and thus
introducing any new reserved prefix in future risks masking an existing
resource type so it can't be used anymore.

We only intend to introduce new reserved symbols as part of future
language editions that each module can opt into separately, and when doing
so we will always research to try to choose a name that doesn't overlap
with commonly-used providers, but not all providers are visible to us and
so there is always a small chance that the name we choose will already be
in use by a third-party provider.

In preparation for that event, this introduces an alternative way to refer
to managed resources that mimics the reference style used for data
resources: resource.type.name . When using this form, the second portion
is _always_ a resource type name and never a reserved word.

There is currently no need to use this because all of the already-reserved
symbol names are effectively blocked from use by existing Terraform
versions that lack this escape hatch. Therefore there's no explicit
documentation about it yet.

The intended use for this is that a module upgrade tool for a future
language edition would detect references to resource types that have now
become reserved words and add the "resource." prefix to keep that
functionality working. Existing modules that aren't opted in to the new
language edition would keep working without that prefix, thus keeping to
compatibility promises.
2021-05-17 11:17:25 -07:00
Martin Atkins 70fed23be5 lang/funcs: File hashing functions stream data from disk
Previously our file hashing functions were backed by the same "read file
into memory" function we use for situations like "file" and "templatefile",
meaning that they'd read the entire file into memory first and then
calculate the hash from that buffer.

All of the hash implementations we use here can calculate hashes from a
sequence of smaller buffer writes though, so there's no actual need for
us to create a file-sized temporary buffer here.

This, then, is a small refactoring of our underlying function into two
parts, where one is responsible for deciding the actual filename to load
opening it, and the other is responsible for buffering the file into
memory. Our hashing functions can then use only the first function and
skip the second.

This then allows us to use io.Copy to stream from the file into the
hashing function in smaller chunks, possibly of a size chosen by the hash
function if it happens to implement io.ReaderFrom.

The new implementation is functionally equivalent to the old but should
use less temporary memory if the user passes a large file to one of the
hashing functions.
2021-05-12 09:28:31 -07:00
Alisdair McDiarmid dbe5272931 functions: Improve marks support for lookup
Several changes to lookup to improve how we handle marked values:

- If the entire collection is marked, preserve the marks on any result
  (whether successful or fallback)
- If a returned value from the collection is marked, preserve the marks
  from only that value, combined with any overall collection marks
- Retain marks on the fallback value when it is returned, combined with
  any overall collection marks
- Include marks on the key in the result, as otherwise the result it
  ends up selecting could imply what the sensitive value was
- Retain collection marks when returning an unknown value for a not
  wholly-known collection

See also https://github.com/zclconf/go-cty/pull/98
2021-05-07 12:55:40 -04:00
Alisdair McDiarmid e0c6b3fcda functions: Improve marks support for length
Similar to cty's implementation, we only need to preserve marks from the
value itself, not any nested values it may contain. This means that
taking the length of an umarked list with marked elements results in an
unmarked number.
2021-05-07 11:57:37 -04:00
James Bardin 4997b9b5bb
Merge pull request #28424 from hashicorp/jbardin/dynamic
Better planing of unknown dynamic blocks
2021-04-23 18:26:21 -04:00
Kristin Laemmert f6af7b4f7a
lang/funcs: add (console-only) TypeFunction (#28501)
* lang/funcs: add (console-only) TypeFunction

The type() function, which is only available for terraform console,
prints out the type of a given value. This is mainly intended for
debugging - it's nice to be able to print out terraform's understanding
of a complex variable.

This introduces a new field for Scope: ConsoleMode. When ConsoleMode is true, any additional functions intended for use in the console (only) may be added.
2021-04-23 10:29:50 -04:00
Kristin Laemmert 5ae4c2f92b lang/funcs: Defaults handling of marked arguments
Defaults will now preserve marks from non-null inputs and apply marks from any default values used. I've added tests for various structural types with marks, as well as some basic unknown cases.
2021-04-21 16:09:09 -04:00
Kristin Laemmert b34588ffca lang/funcs: TransposeFunc Tests
This commit adds test cases to TestTranspose to document how this function handles marks.

The short version is that any marks anywhere will be applied to the return value, be they marks on the input map or marks on elements (either the entire list of strings, or individual elemnets of those lists).
2021-04-21 16:09:09 -04:00
Martin Atkins 14336ae6f8 lang/funcs: Conversion functions can handle sensitive values
In order to avoid updating every one of our existing functions with
explicit support for sensitive values, there's a default rule in the
functions system which makes the result of a function sensitive if any
of its arguments contain sensitive values.

We were applying that default to the various type conversion functions,
like tomap and tolist, which meant that converting a complex-typed value
with a sensitive value anywhere inside it would result in a
wholly-sensitive result.

That's unnecessarily conservative because the cty conversion layer (which
these functions are wrapping) already knows how to handle sensitivity
in a more precise way. Therefore we can opt in to handling marked values
(which Terraform uses for sensitivity) here and the only special thing
we need to do is handle errors related to sensitive values differently,
so we won't print their values out literally in case of an error (and so
that the attempt to print them out literally won't panic trying to
extract the marked values).
2021-04-19 12:10:50 -07:00
James Bardin b515ab583a make blocktoattr an hcldec.UnknownBody
This will allow any dynamic blocks that are fixed up as a blocktoattr
still decode into an unknown value.
2021-04-13 18:42:15 -04:00
Martin Atkins 140c613ae8 lang/funcs: "one" function
In the Terraform language we typically use lists of zero or one values in
some sense interchangably with single values that might be null, because
various Terraform language constructs are designed to work with
collections rather than with nullable values.

In Terraform v0.12 we made the splat operator [*] have a "special power"
of concisely converting from a possibly-null single value into a
zero-or-one list as a way to make that common operation more concise.

In a sense this "one" function is the opposite operation to that special
power: it goes from a zero-or-one collection (list, set, or tuple) to a
possibly-null single value.

This is a concise alternative to the following clunky conditional
expression, with the additional benefit that the following expression is
also not viable for set values, and it also properly handles the case
where there's unexpectedly more than one value:

    length(var.foo) != 0 ? var.foo[0] : null

Instead, we can write:

    one(var.foo)

As with the splat operator, this is a tricky tradeoff because it could be
argued that it's not something that'd be immediately intuitive to someone
unfamiliar with Terraform. However, I think that's justified given how
often zero-or-one collections arise in typical Terraform configurations.
Unlike the splat operator, it should at least be easier to search for its
name and find its documentation the first time you see it in a
configuration.

My expectation that this will become a common pattern is also my
justification for giving it a short, concise name. Arguably it could be
better named something like "oneornull", but that's a pretty clunky name
and I'm not convinced it really adds any clarity for someone who isn't
already familiar with it.
2021-04-12 15:32:03 -07:00
Alisdair McDiarmid c1f7193454 lang/funcs: Make nonsensitive more permissive
Calling the nonsensitive function with values which are not sensitive
will result in an error. This restriction was added with the goal of
preventing confusingly redundant use of this function.

Unfortunately, this breaks when using nonsensitive to reveal the value of
sensitive resource attributes. This is because the validate walk does
not (and cannot) mark attributes as sensitive based on the schema,
because the resource value itself is unknown.

This commit therefore alters this restriction such that it permits
nonsensitive unknown values, and adds a test case to cover this specific
scenario.
2021-04-12 12:31:59 -04:00
Martin Atkins 89b2405080 lang/funcs: "sensitive" and "nonsensitive" functions
These aim to allow hinting to Terraform about situations where it's not
able to automatically infer value sensitivity.

"nonsensitive" is for situations where Terraform's behavior is too
conservative, such as when a new value is derived from a sensitive value
in such a way that all of the sensitive content is removed.

"sensitive", on the other hand, is for situations where Terraform can't
otherwise infer that a value is sensitive. These situations should be
pretty rare in a module that's making effective use of sensitive input
variables and output values, but the documentation shows one example of
an uncommon situation where a more direct hint via this function would
be needed.

Both of these functions are aimed at only occasional use in unusual
situations. They are here for reasons of pragmatism, not because we
expect them to be used routinely or recommend their use.
2021-03-16 16:26:22 -07:00
Alisdair McDiarmid 7f97bd4489 functions: Fix missing defaults for objects/tuples
If no default is specified for a nested optional structural typed
attribute, the defaults function should just pass through its input.
Before this commit the function assumed that the fallback value was
always of the correct type, which would panic.
2021-03-12 18:14:14 -05:00
Alisdair McDiarmid 0bbe583eb8 functions: Fix defaults for null objects/tuples
When using defaults with a value which contains null objects or tuples,
we cannot continue to traverse the value and apply defaults. Instead,
when we find an attribute which is null, we return early and stop
processing this branch.
2021-03-12 08:23:41 -05:00
Alisdair McDiarmid 66f8d1c1c2 functions: Fix defaults mismatched types fallback
We allow primitive fallback values which have mismatched types, but only
if there is a conversion to the target type. Previously we would allow
unsafe conversions (e.g. string to bool), but later had no capacity to
return an error if the conversion failed due to the value of the
fallback being unable to convert to the target type.

This commit makes the more conservative requirement that default
fallback values must have a safe conversion.
2021-03-04 10:43:09 -05:00
Alisdair McDiarmid 178a9b32d7 functions: Fix defaults null collections panic
When applying default values to collection types, null collections in
the input should result in empty collections in the output.
2021-03-04 10:13:41 -05:00
njucz e62979acfe fix slash issue on windows 2021-01-15 15:53:06 +08:00
Alisdair McDiarmid f27dae2ab7 lang: Improved robustness of sum function
Fixes error when calling sum with values not known until apply time.
Also allows sum to cope with numbers too large to represent in float64,
along with correctly handling errors when trying to sum opposing
infinities.
2020-12-10 17:13:56 -05:00
Alisdair McDiarmid df626e898c lang/funcs: Fix alltrue/anytrue with unknowns
The alltrue/anytrue functions did not correctly handle unknown values.
This commit changes these functions so that the result is unknown if:

- The list argument is unknown
- For alltrue: any elements are unknown
- For anytrue: any elements are unknown and no known elements are true

The last change is a little subtle, so there are test cases to cover it
specifically. Examples:

- anytrue(unknown) -> unknown
- anytrue(false, unknown) -> unknown
- anytrue(false, unknown, true) -> true
2020-12-10 11:36:14 -05:00
James Bardin e08422511e lang/funcs: staticcheck 2020-12-02 13:59:19 -05:00
Pam Selle c55b69e30a Fix diags non-assignment bugs
Fix places where diags was not reassigned when diags were added.
2020-11-20 13:37:23 -05:00
Martin Atkins cec4578005 lang/funcs: Experimental "defaults" function
This is a new part of the existing module_variable_optional_attrs
experiment, because it's intended to complement the ability to declare
an input variable whose type constraint is an object type with optional
attributes. Module authors can use this to replace null values (that were
either explicitly set or implied by attribute omission) with other
non-null values of the same type.

This function is a bit more type-fussy than our functions typically are
because it's intended for use primarily with input variables that have
fully-specified type constraints, and thus it uses that type information
to help inform how the defaults data structure should be interpreted.

Other uses of this function will probably be harder today because it takes
a lot of extra annotation to build a value of a specific type if it isn't
passing through a variable type constraint. Perhaps later language
features for more general type conversion will make this more applicable,
but for now the more general form of this problem is better solved other
ways.
2020-11-13 17:27:20 -08:00
Martin Atkins c8843642c8 lang: allow functions to be subject to experiments
So far all of our language experiments have been new constructs handled
statically up in the configs package, but functions are another common
extention point where experiments could be useful to gather feedback and
so this intends to pass the information down into the right place to allow
for that to happen, even though as of this commit there are no
experimental functions to use it.
2020-11-13 17:25:16 -08:00
Martin Atkins ae3c0c6a4a lang/funcs: Remove the deprecated "list" and "map" functions
Prior to Terraform 0.12 these two functions were the only way to construct
literal lists and maps (respectively) in HIL expressions. Terraform 0.12,
by switching to HCL 2, introduced first-class syntax for constructing
tuple and object values, which can then be converted into list and map
values using the tolist and tomap type conversion functions.

We marked both of these functions as deprecated in the Terraform v0.12
release and have since then mentioned in the docs that they will be
removed in a future Terraform version. The "terraform 0.12upgrade" tool
from Terraform v0.12 also included a rule to automatically rewrite uses
of these functions into equivalent new syntax.

The main motivation for removing these now is just to get this change made
prior to Terraform 1.0. as we'll be doing with various other deprecations.
However, a specific reason for these two functions in particular is that
their existence is what caused us to invent the idea of a "type expression"
as a distinct kind of expression in Terraform v0.12, and so removing them
now would allow potentially  unifying type expressions with value
expressions in a future release.

We do not have any current specific plans to make that change, but one
potential motivation for doing so would be to take another attempt at a
generalized "convert" function which takes a type as one of its arguments.
Our previous attempt to implement such a function was foiled by the fact
that Terraform's expression validator doesn't have any way to know to
treat one argument of a particular function as special, and so it was
generating incorrect error messages. We won't necessarily do that, but
having these "list" and "map" functions out of the way leaves the option
open.
2020-11-04 17:05:59 -08:00
James Bardin 7c4d00c04c allow path and terraform in self-block eval
We can insert the terraform and path values into EvalSelfBlock, since
these are static and always known during evaluation.
2020-11-02 14:00:58 -05:00
Martin Atkins e2c64bc255 core: Annotate for_each errors with expression info
Our diagnostics model allows for optionally annotating an error or warning
with information about the expression and eval context it was generated
from, which the diagnostic renderer for the UI will then use to give the
user some additional hints about what values may have contributed to the
error.

We previously didn't have those annotations on the results of evaluating
for_each expressions though, because in that case we were using the helper
function to evaluate an expression in one shot and thus we didn't ever
have a reference to the EvalContext in order to include it in the
diagnostic values.

Now, at the expense of having to handle the evaluation at a slightly lower
level of abstraction, we'll annotate all of the for_each error messages
with source expression information. This is valuable because we see users
often confused as to how their complex for_each expressions ended up being
invalid, and hopefully giving some information about what the inputs were
will allow more users to self-solve.
2020-10-29 09:07:48 -07:00
Arthur Burkart d4716a69e1
lang/funcs: "anytrue" function
This is an analog to the "alltrue" function, using OR as the reduce
operator rather than AND.

This also includes some simplification of the "alltrue" implementation
to implement it similarly as a sort of reduce operation with AND
as the reduce operator, but with the same effective behavior.
2020-10-23 13:52:48 -07:00
Martin Atkins 1dc4950bfa lang/funcs: Rename the base64 character encoding functions
These were initially introduced as functions with "encode" and "decode"
prefixes, but that doesn't match with our existing convention of putting
the encoding format first so that the encode and decode functions will
group together in a alphabetically-ordered function list.

"text" is not really a defined serialization format, but it's a short word
that hopefully represents well enough what these functions are aiming to
encode and decode, while being consistent with existing functions like
jsonencode/jsondecode, yamlencode/yamldecode, etc.

The "base64" at the end here is less convincing because there is precedent
for that modifier to appear both at the beginning and the end in our
existing function names. I chose to put it at the end here because that
seems to be our emergent convention for situations where the base64
encoding is a sort of secondary modifier alongside the primary purpose
of the function, as we see with "filebase64". (base64gzip is an exception
here, but it seems outvoted by the others.)
2020-10-21 10:56:56 -07:00
r0bnet 877399c631 lang/funcs: Functions for encoding text in specific character encodings 2020-10-21 10:39:43 -07:00
James Bardin dd8a8bdea1 add benchmark used for DecoderSpec
Not a great benchmark, but record it here for posterity. Practical
testing with the AWS provider gives us a 98% speedup for simple plans.
2020-10-14 09:19:26 -04:00
James Bardin c48af3f18b
Merge pull request #26470 from hashicorp/jbardin/inverse-destroy-references
Allow special-case evaluation of instances pending deletion.
2020-10-05 16:20:22 -04:00
OwenTuz bb39fafbe5
lang/funcs: lookup() will only treat map as unknown if it is wholly unknown (#26427)
Fix for issue #26320 - this allows us to derive known values from
partially known maps where we can, and may prevent unnecessary
destroy/rebuild cycles during apply in some cases.
2020-10-05 08:48:49 -04:00
James Bardin 64c3a8f550 lang.Scope.EvalSelfBlock
In order to properly evaluate a destroy provisioner, we cannot rely on
the usual evaluation context, because the resource has already been
removed from the state.

EvalSelfBlock evaluates an hcl.Body in the limited scope of a single
object as "self", with the added values of "count.index" and "each.key".
2020-10-02 11:25:21 -04:00
Arthur Burkart 6ed47c7241
lang/funcs: Add "alltrue" function (#25656)
This commit adds an `alltrue` function to Terraform configuration. A
reason we might want this function is because it will enable more
powerful custom variable validations. For example:

```hcl
variable "amis" {
  type = list(object({
    id = string
  }))

  validation {
    condition = (alltrue([
      for a in var.amis : length(a.id) > 4 && substr(a.id, 0, 4) == "ami-"
    ]))
    error_message = "The ID of at least one AMI was invalid."
  }
}
```
2020-09-22 09:06:42 -04:00
Alisdair McDiarmid c7568ccceb lang: Add test for jsonencode entity escaping
The encoding/json package escapes some HTML-specific characters to
prevent JSON from being misinterpreted when in the context of an HTML
document. Terraform 0.11 used this behaviour, and to preserve backwards
compatibility we are continuing to do so moving forward.

This commit adds an explicit test to document that this is intentional,
not a bug.
2020-09-04 09:18:52 -04:00
Kristin Laemmert e639d813ee add test cases and remove no-longer-needed validation 2020-07-08 13:53:54 -04:00
Kristin Laemmert 384cfaacf9 lang/funcs: refactor Subnet and Host functions to support 64-bit systems 2020-07-08 10:58:06 -04:00
Martin Atkins 8f77bd344e lang/funcs: Filesystem functions hint about dynamically-generated files
The functions that interact with the filesystem are, by design, restricted
to reading files that are distributed as a static part of the
configuration, and cannot be used to interact with files that are
generated dynamically by resources in the configuration.

However, new users have often yet developed a correct mental model of how
Terraform execution works and are confused by the terse error messages
these functions return. As an interim step to help some of those users,
this just adds some more commentary to the error message which gives a
vague, generic directive to look to attributes of the resource that is
generating the file, which should (if it's designed well) export
attributes that allow the resulting file to be used effectively with
common patterns, such as checksums of the content of the generated file.

The error message here is not particularly attractive due to the
limitations of the context where it's being returned from, but I'm
accepting that here in the interest of keeping this change simple, so we
can give a hint about a case that seems to frequently generate new-user
questions. We may iterate further on the presentation of this message
later.
2020-06-24 09:02:38 -07:00
Alisdair McDiarmid 80ca4db54d lang: Add regression test for yamldecode bug 2020-06-17 13:05:14 -04:00
Alisdair McDiarmid a4f5e04066 lang/funcs: Add support for OpenSSH RSA key format
Previously this function only supported the x509 RSA private key format.
More recent versions of OpenSSH default to generating a new PEM key
format, which this commit now supports using the x/crypto/ssh package.

Also improve the returned error messages for various invalid ciphertext
or invalid private key errors.
2020-06-03 10:50:38 -04:00
Daniel Dreier 0749e419de
Merge pull request #24484 from ctjhoa/fix_typo
fix typo in Base64DecodeFunc log
2020-05-04 16:11:47 -07:00
James Bardin 6c0f7703a6
Merge pull request #24697 from hashicorp/jbardin/get-module-data
Always return all module instances during evaluation
2020-04-22 09:49:45 -04:00
Noah Mercado d4d8812afa
Feature: Sum Function (#24666)
The sum function takes a list or set of numbers and returns the sum of those
numbers.
2020-04-15 14:27:06 -04:00
James Bardin 42cee86ee2 remove GetModuleInstanceOutput
There is no codepath that can use this any longer, since we need to
evaluate the modules as whole objects.

This means we're going to have to live for now with invalid module
output references returning "object" errors rather that "module".
2020-04-14 14:49:10 -04:00
James Bardin 600d4c3e1f eval Data needs to operate on whole modules
In order to be able to use module values, and handle operations like
possibly invalid module indexes in conditional statements, whole modules
must always be returned during evaluation.
2020-04-12 10:50:31 -04:00
Camille TJHOA d7f711f40e fix typo in Base64DecodeFunc log 2020-03-27 17:22:40 +00:00
Pam Selle f738f85241 Create non-specific ModuleCallOutput 2020-03-26 13:29:38 -04:00
Alisdair McDiarmid 37006c5841 lang: Fix non-string key panics in map function
The map function assumed that the key arguments were strings, and would
panic if they were not.

After this commit, calling `map(1, 2)` will result in a map `{"1" = 1}`,
and calling `map(null, 1)` will result in a syntax error.

Fixes #23346, fixes #23043
2020-03-04 10:54:55 -05:00
James Bardin 0bd40fd496
Merge pull request #24265 from hashicorp/jbardin/cty-update
Update cty to v1.3.1 and migrate to cty stdlib function where applicable
2020-03-04 09:33:51 -05:00